/*  ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** 
*   Copyright 2014 Jan-Marwin Wollschläger                                   *
*                                                                            *
*   Licensed under the Apache License, Version 2.0 (the "License");          *
*   you may not use this file except in compliance with the License.         *
*   You may obtain a copy of the License at                                  *
*                                                                            *
*       http://www.apache.org/licenses/LICENSE-2.0                           *
*                                                                            *
*   Unless required by applicable law or agreed to in writing, software      *
*   distributed under the License is distributed on an "AS IS" BASIS,        *
*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
*   See the License for the specific language governing permissions and      *
*   limitations under the License.                                           *
** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **   */  

import processing.core.*;

public class DefaultMoleculeRenderer implements IMoleculeRenderer
{
	private int r;
	private int g;
	private int b;
	private float sigmaBondLabelCorrection = 0.3f;
	private float piBondSpacing = 0.7f;
	
	public DefaultMoleculeRenderer()
	{
		r = 0; g = 0; b = 0;
	}
	
    /**
    * Draws the specified Molecule molecule in the PApplet parent.
    * @param parent The PApplet to draw on.
    * @param molecule The molecule to draw.
    **/
    public void renderMolecule(PApplet parent, IMolecule molecule)
    {
	  /* Needed to draw with the right color */
      parent.stroke(r,g,b);
	  parent.fill(r,g,b);
	  
	  /* Render the atom symbol text at the right coordinates */
	  parent.textAlign(parent.CENTER, parent.CENTER);
	  
	  /* Iterate over all atoms */	
      for(IAtom atom : molecule.getAtoms())
      {
		/* Draw the atom label only if atom is not implicit */
		if(!molecule.isAtomImplicit(atom))
			parent.text(atom.getLabel(), atom.getPosition().getX(),
						atom.getPosition().getY());
      }
      
      /* Iterate over all bonds */
      for(IBond bond : molecule.getBonds())
      {
		  IVector2 p1 = bond.getFirstAtom().getPosition();
		  IVector2 p2 = bond.getSecondAtom().getPosition();
		  
		  if(bond.getOrder() == 1)
		  {// It's a single bond
		    /* Create a line from one atom to the other atom */
			ILine bndLine = new Line(p1, p2);
			
			if(!molecule.isAtomImplicit(bond.getFirstAtom()) && 
				!molecule.isAtomImplicit(bond.getSecondAtom()))
			{  // So both atoms are rendered with their atom symbol
			    final float shrinkFactor = (bndLine.getLen()//
					-parent.textWidth(bond.getFirstAtom().getLabel())
					-parent.textWidth(bond.getSecondAtom().getLabel()))
					/bndLine.getLen(); 
				bndLine = bndLine.shrink(shrinkFactor-sigmaBondLabelCorrection);  
			}
			
			/* Draw the line onto the PApplet */
			parent.line(bndLine.getFirstPoint().getX(),
						bndLine.getFirstPoint().getY(),
						bndLine.getSecondPoint().getX(),
						bndLine.getSecondPoint().getY());
          }
          else  // It's not a single bond
          if(bond.getOrder() == 2)
          {// It's a double bond
			  /* Single ("sigma") bond is directly connecting both atoms */
			  ILine sigmaBond = new Line(p1, p2);
			  
			  /* Draw the sigma bond as before (in the single bond case) */
			  if(!molecule.isAtomImplicit(bond.getFirstAtom()) && 
				!molecule.isAtomImplicit(bond.getSecondAtom()))
			  {  // So both atoms are rendered with their atom symbol
					final float shrinkFactor = (sigmaBond.getLen()//
					-parent.textWidth(bond.getFirstAtom().getLabel())
					-parent.textWidth(bond.getSecondAtom().getLabel()))
					/sigmaBond.getLen(); 
					sigmaBond = sigmaBond.shrink(shrinkFactor-sigmaBondLabelCorrection);
			  }
			  
			  /* Calculate the orthogonal to this sigma bond */
			  IVector2 orthogonal = sigmaBond.getOrthogonalDirection();
			  
			  /* The vector orthogonal has now the same length as the sigma bond,
			  *  this is to long for the typical spacing between the sigma and pi 
			  *  bonds, so the vector orthogonal has to be shrinked.
			  */
			  orthogonal = orthogonal.mult(1.0f - piBondSpacing);
			  
			  IVector2 piPoint1 = sigmaBond.getFirstPoint().vecPlus(orthogonal);
			  IVector2 piPoint2 = sigmaBond.getSecondPoint().vecPlus(orthogonal);
			  
			  ILine piBond = new Line(piPoint1, piPoint2);
			   
			  /* Draw the single (sigma) bond line onto the PApplet */
			  parent.line(sigmaBond.getFirstPoint().getX(),
						sigmaBond.getFirstPoint().getY(),
						sigmaBond.getSecondPoint().getX(),
						sigmaBond.getSecondPoint().getY());
			  
			  /* Draw the double (pi) bond line onto the PApplet */
			  parent.line(piBond.getFirstPoint().getX(),
						piBond.getFirstPoint().getY(),
						piBond.getSecondPoint().getX(),
						piBond.getSecondPoint().getY());
		  }
      }
    } 
}
